#include "StdAfx.h"
#include "LuabindScriptModule.h"
#include "UIString.h"
#include "UIDatas.h"
#include "UIPropertySet.h"
#include "UIWidget.h"
#include "UIUtility.h"
#include "UIEventSet.h"
#include "../CreationAssist/Console.h"

struct LuabindDelegate
{
	std::string target;
	lua_State *l;

	LuabindDelegate(lua_State* state,const std::string& functionName):l(state),target(functionName)
	{

	}

	bool operator()(const CEGUI::EventArgs& e)
	{
		return luabind::call_function<bool>(l,target.c_str(),e);
	}

	operator CEGUI::Event::Subscriber()
	{
		return CEGUI::Event::Subscriber(this);
	}
};

using namespace CEGUI;

ScriptBackend::LuabindScriptModule::LuabindScriptModule( lua_State* l ,Callback_OnDestroyBindings odb) :
luaState(l),
onDestroyBindings(odb)
{
	d_identifierString="Luabind scripting module";
}

ScriptBackend::LuabindScriptModule::~LuabindScriptModule( void )
{

}

void ScriptBackend::LuabindScriptModule::createBindings( void )
{
	Module_UIString(luaState);
	Module_UIDatas(luaState);
	Module_UIPropertySet(luaState);
	Module_UIEventSet(luaState);
	Module_UIWidget(luaState);
}

void ScriptBackend::LuabindScriptModule::destroyBindings( void )
{
	if(onDestroyBindings!=0)
		onDestroyBindings();
}

Event::Connection ScriptBackend::LuabindScriptModule::subscribeEvent( EventSet* target, const String& name, const String& subscriber_name )
{
	return target->subscribeEvent(name,LuabindDelegate(luaState,subscriber_name.c_str()));
}

Event::Connection ScriptBackend::LuabindScriptModule::subscribeEvent( EventSet* target, const String& name, Event::Group group, const String& subscriber_name )
{
	return target->subscribeEvent(name,group,LuabindDelegate(luaState,ScriptBackend::UIUtility::toStdString(subscriber_name)));
}

int ScriptBackend::LuabindScriptModule::executeScriptGlobal( const String& function_name )
{
	return luabind::call_function<int>(luaState,ScriptBackend::UIUtility::toStdString(function_name).c_str());
}

void ScriptBackend::LuabindScriptModule::executeString( const String& str )
{
	CA::Console::Eval(ScriptBackend::UIUtility::toStdString(str));
}

bool ScriptBackend::LuabindScriptModule::executeScriptedEventHandler( const String& handler_name, const EventArgs& e )
{
	return luabind::call_function<bool>(luaState,ScriptBackend::UIUtility::toStdString(handler_name).c_str(),e);
}

void ScriptBackend::LuabindScriptModule::executeScriptFile( const String& filename, const String& resourceGroup /*= ""*/ )
{
	using namespace CEGUI;
	
	int top = lua_gettop(luaState);

	RawDataContainer raw;
	System::getSingleton().getResourceProvider()->loadRawDataContainer(filename,
		raw, resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup);

	// load code into lua
	int loaderr = luaL_loadbuffer(luaState,
		reinterpret_cast<char*>(raw.getDataPtr()),
		raw.getSize(), filename.c_str());

	System::getSingleton().getResourceProvider()->unloadRawDataContainer( raw );

	if (loaderr)
	{
		String errMsg = lua_tostring(luaState,-1);
		lua_settop(luaState,top);
		throw ScriptException("Unable to execute Lua script file: '" +
			filename + "'\n\n" + errMsg + "\n");
	}

	// call it
	lua_call(luaState, 0, 0);
	
	lua_settop(luaState,top);
}